/* Include files. */

extern "C" { 
	#include "standard.h"
	#include "util.h"
	#include "debug.h"
} 
#include "network.h"
#include "nettr069.h"
#include "subsystemcore.h"

/* Local function declarations. */

/* Macro API definitions. */

/* Global variable declarations. */

/* Type definitions. */

/* Local function definitions. */

nettr069::nettr069(u32 ip, u16 port, u32 fd)
		:netObject(ip, port, fd)
{
	_agent_name = string("access");
	_status = BEGIN;
	_finish = 0;
	_header_finish = 0;
	_buff = NULL;
}

nettr069::~nettr069()
{
	if (_buff != NULL) {
		free(_buff);
	}
}

int nettr069::bind()
{
	int ret;
	
	if (subSystem::bindSubSystem(_agent_name, this)) {
		DEBUG("new connection " NIPQUAD_FMT ":%d , netobj = %p, socket = %d, id = %u\n",
		 NIPQUAD(_ip), _port, this, _fd, _id);
		ret = 1;
	}
	else {
		ERROR("%s service don't start!\n", _agent_name.c_str());
		ERROR("bind faild, " NIPQUAD_FMT ":%d , netobj = %p, socket = %d, id = %u\n",
		  NIPQUAD(_ip), _port, this, _fd, _id);
		ret = 0;
	}

	return ret;
}

int nettr069::allocbuff()
{	
	if (_buff != NULL) {
		free(_buff);
	}
	_buff = (char*)malloc(_header.len + 1);
	if (_buff == NULL) {
		ERROR("alloc buff faild %d\n", _header.len);
		_buff = NULL;
		return e_ERROR;
	}
	_buff[_header.len] = '\0';
	return e_OK;
}

int nettr069::readHeader()
{	
	int ret = netRecv(_fd, (u8 *)&_header, sizeof(_header));
	if (ret < 0) {
		return e_ERROR;
	}
	else if (ret == 0) {
		return e_CONTINUE;
	}
	else {
		_header_finish += ret;
		if (_header_finish < (int)sizeof(_header)) {
			return e_CONTINUE;
		}
		else if  (_header_finish == sizeof(_header)) {
			_header.len = ntohl(_header.len);
			return e_OK;
		}
		else
			return e_ERROR;
	} 
}

int nettr069::readData()
{	
	int ret = netRecv(_fd, (u8 *)&_buff[_finish], _header.len-_finish);
	if (ret < 0) {
		return e_ERROR;
	}
	else if (ret == 0) {
		return e_CONTINUE;
	}
	else {
		_finish += ret;
		if (_finish < _header.len) {
			return e_CONTINUE;
		}
		else if  (_finish == _header.len) {
			return e_OK;
		}
		else
			return e_ERROR;
	} 
}

int nettr069::recvMsg()
{
	int ret;

	while(1) {
		switch(_status) {
			case BEGIN:
				ret = readHeader();
				if (ret != e_OK) {
					return ret;
				}
				_status = ALLOC_DATA;
			case ALLOC_DATA:
				ret = allocbuff();
				if (ret != e_OK) {
					return ret;
				}
				_status = READ_DATA;
			case READ_DATA:
				ret = readData();
				if (ret != e_OK) {
					return ret;
				}
				ASSERT(_buff[_header.len] == '\0');
				//DEBUG("len = %d, buff = %s\n", _header.len, _buff);
				sendSubSystem(_sub->_L, "easycwmp", _sub->_name.c_str(), 
					"tr069", _buff, _id);
				_status = END;
				return e_OK;
			case END:
				_finish = 0;
				memset(&_header, 0, sizeof(_header));
				_status = BEGIN;
		}
	}
}

int nettr069::sendMsg()
{
	string s = _out_queue.front();
	_out_queue.pop();
	int len = htonl(s.size());
	int n = netSend(_fd, (u8 *)&len, sizeof(len));
	n = netSend(_fd, (u8 *)s.c_str(), s.size());
	if (n >= 0) {
		return e_OK;
	}
	else {
		WARN("send data failed, %s\n", strerror(errno));
		return e_ERROR;
	}	
}



